import * as THREE from "three";
// 引入轨道控制器扩展库OrbitControls.js
import { OrbitControls } from "three/addons/controls/OrbitControls.js";
import ThreeJsPhysicsWorld from "./ThrreJsPhysicsWorld";

export default class ThreeJsWorld {
  constructor() {
    this.controls = null;
    this.canvas = null;
    this.worldWidth = 2000;
    this.worldHeight = 1000;
    this.objs = []; // 所有的物体：{可视化物体，物理物体}
    this.scene = null;
    this.camera = null;
    this.renderer = null;
    this.world = null;
    this.updateWorldFuns = [];
    this.physicsWorld = null;
    this.maxSurvivalTime = 30; // 单位秒
  }

  initWorld(options) {
    this.initOption(options);
    this.createScence(options);
    this.createCamera(options);
    this.createRenderer(options);
    this.addLight();
    this.initPhysicsWorld();
  }
  initPhysicsWorld() {
    this.physicsWorld = new ThreeJsPhysicsWorld(this);
    this.physicsWorld.initWorld();
  }
  initOption(options) {
    if (options.hasOwnProperty("width")) {
      this.worldWidth = options.width;
    }
    if (options.hasOwnProperty("height")) {
      this.worldHeight = options.height;
    }
    if (options.hasOwnProperty("canvas")) {
      this.canvas = options.canvas;
    }
    console.log(this);
  }
  addLight() {
    const directionalLight = new THREE.DirectionalLight(0xffffff, 1);
    directionalLight.position.set(10, 6, 5);
    this.scene.add(directionalLight);
    const ambient = new THREE.AmbientLight(0xffffff, 0.6);
    this.scene.add(ambient);
  }
  addWorldGround() {
    const planeGeometry = new THREE.PlaneGeometry(20, 20);
    const planeMaterial = new THREE.MeshLambertMaterial({
      color: 0x808080,
    });
    const planeMesh = new THREE.Mesh(planeGeometry, planeMaterial);
    planeMesh.rotateX(-Math.PI / 2);
    this.scene.add(planeMesh);
    this.addWorldWall();
  }
  addWorldWall() {
    // 立方体
    const box = new THREE.Mesh(
      new THREE.BoxGeometry(20, 100, 0.1),
      new THREE.MeshStandardMaterial({ color: 0xff8888 })
    );
    box.position.set(0, 50, -10);
    this.scene.add(box);
    this.physicsWorld.addBox(box, 0, true);

    const box1 = new THREE.Mesh(
      new THREE.BoxGeometry(20, 100, 0.1),
      new THREE.MeshStandardMaterial({ color: 0xff8888 })
    );
    box1.position.set(-10, 50, 0);
    box1.rotateY(-Math.PI / 2);
    this.scene.add(box1);
    this.physicsWorld.addBox(box1, 0, true);
  }
  addSphere(radius, x, y, z) {
    const geometry = new THREE.SphereGeometry(radius);
    const material = new THREE.MeshLambertMaterial({
      color: 0xffff00,
    });
    const mesh = new THREE.Mesh(geometry, material);
    mesh.position.set(x, y, z);
    this.scene.add(mesh);
    return this.physicsWorld.addSphere(mesh);
  }
  addBox(width, height, depth, x, y, z) {
    // 立方体
    const box = new THREE.Mesh(
      new THREE.BoxGeometry(width, height, depth),
      new THREE.MeshStandardMaterial({ color: 0xff0000 })
    );
    box.position.set(x, y, z);
    this.scene.add(box);
    return this.physicsWorld.addBox(box);
  }
  addObj(obj, objBody) {
    // 可视化物体，物理物体
    const compObj = { obj, objBody, createDate: new Date() };
    this.objs.push(compObj);
    return compObj;
  }
  getObjs() {
    return this.objs;
  }
  createScence(options) {
    this.scene = new THREE.Scene();
    this.scene.background = new THREE.Color(0xb2b2b2);
    //辅助观察的坐标系
    const axesHelper = new THREE.AxesHelper(10);
    this.scene.add(axesHelper);
  }
  createCamera(options) {
    this.camera = new THREE.PerspectiveCamera(
      30,
      this.worldWidth / this.worldHeight,
      1,
      3000
    );
  }
  createRenderer(options) {
    this.renderer = new THREE.WebGLRenderer({
      antialias: true, //开启优化锯齿
      canvas: this.canvas,
    });
    this.renderer.setPixelRatio(window.devicePixelRatio); //防止输出模糊
    this.renderer.setSize(this.worldWidth, this.worldHeight);
  }
  setCameraPosition(x, y, z) {
    this.camera.position.set(x, y, z);
    this.camera.lookAt(0, 0, 0);
  }
  startWorld() {
    this.controls = new OrbitControls(this.camera, this.renderer.domElement);
    this.physicsWorld.startWorld();
    this.updateWorld();
  }
  registeUpdateFun(fun) {
    this.updateWorldFuns.push(fun);
  }
  updateObjects() {
    this.objs.forEach(({ obj, objBody }) => {
      obj.position.copy(objBody.position);
      obj.quaternion.copy(objBody.quaternion);
    });
  }
  updateWorld() {
    this.updateObjects();
    this.updateWorldFuns.forEach((fun) => {
      fun.apply();
    });
    this.renderer.render(this.scene, this.camera);
    requestAnimationFrame(() => {
      this.updateWorld();
    });
  }
  setMaxSurvivalTime(maxSurvivalTime) {
    this.maxSurvivalTime = maxSurvivalTime;
  }
  clearObj() {
    const deadArr = this.objs.filter(({ createDate }) =>
      this.isDead(createDate)
    );
    this.objs = this.objs.filter(({ createDate }) => !this.isDead(createDate));
    deadArr.forEach(({ obj, objBody }) => {
      this.scene.remove(obj);
      this.physicsWorld.removeObj(objBody);
    });
  }
  isDead(createDate) {
    return this.isOlderThanOfSeconds(createDate, this.maxSurvivalTime);
  }
  isOlderThanOfSeconds(date, seconds) {
    const now = new Date(); // 当前时间
    const diffInSeconds = (now.getTime() - date.getTime()) / 1000; // 时间差（秒）

    return diffInSeconds > seconds;
  }
}
